Table toolbar
A centralized location for managing and interacting with tabular data, offering functions like filtering, searching, exporting, and other table-related actions.
#Examples
#Usage with actions
Provide essential actions that operate on the entire table's data. Limit to two actions that directly support the table's main purpose.
Best Practices:
- Place the most frequent or crucial actions first.
- Use concise labels and relevant icons for easy identification.
- Ideally, no more than two actions should be exposed as buttons. Use an Action Menu for additional actions.
<TableToolbar
actions={
<>
<Button variant="primary" onClick={() => console.log("some primary action")}>
Primary
</Button>
<Button variant="secondary" onClick={() => console.log("some secondary action")}>
Secondary
</Button>
</>
}
/>
#Usage with filter
Allow users to refine table data based on specific criteria.
Best Practices:
- Use a Filter Group to house multiple filters, maintaining a clean toolbar.
- When filters are active, display filter pills (removable tags) directly on the toolbar to indicate the applied criteria.
Here is an example using a single filter that allow users to search for specific keywords (e.g country) within the table. Learn how to use filter groups in the guidelines for the Filters component.
type Country = { id: string; name: string };
const countries: Country[] = [
{ id: "DK", name: "Denmark" },
{ id: "SE", name: "Sweden" },
{ id: "NO", name: "Norway" },
{ id: "FI", name: "Finland" },
];
const [country, setCountry] = useState<Country | undefined>(countries[0]);
const onChange = (newValue: Country | undefined) => {
console.log("Filter changed, calling API with new country", newValue);
setCountry(newValue);
};
const [filterButton, activeFilters] = useSingleFilter(country, onChange, {
label: "Country",
name: "country",
stringify: (country) => country?.name,
items: countries.map((country) => ({ title: country.name, value: country })),
compareFn: (a, b) => a.id === b.id,
});
return <TableToolbar filter={filterButton} activeFilters={activeFilters} />;
#Usage with search
Enable quick location of items or information within the table.
Best Practices:
- Instant Feedback: Provide real-time visual feedback (e.g., highlighting or filtering results) as users type.
- Autocomplete (optional): Consider an Autocomplete component to suggest search terms.
const [searchValue, setSearchValue] = useState("");
const searchTypeItems = ["URL", "Title"];
const [selectedSearchType, setSelectedSearchType] = useState<string | undefined>(
searchTypeItems[0]
);
return (
<TableToolbar
search={
<InputFieldWithSlug
aria-label="Search the table"
placeholder="Search"
name="searchInput"
value={searchValue}
onChange={setSearchValue}
leftSlug={
<Select
items={searchTypeItems.map((x) => ({ value: x, title: x }))}
value={selectedSearchType}
onChange={setSelectedSearchType}
hideClearButton
aria-label="Search in URL or title"
/>
}
rightSlug={
<Button onClick={() => console.log(searchValue)} aria-label="Submit search">
<Icon>
<IconSearch />
</Icon>
</Button>
}
/>
}
/>
);
#Usage with custom views
Allow users to personalize the table's appearance or data display.
#Button
Opens a menu with predefined views or customization options (e.g., "Accessibility Issue" view).
return (
<TableToolbar
customViews={
<Button>
<Icon>
<IconColumn />
</Icon>
<InlineText>Custom views</InlineText>
</Button>
}
/>
);
#Toggle switch
Ideal for binary choices like "Compact" vs. "Detailed" view. (e.g. Performance > Page overview)
Best Practices:
- Use descriptive labels for each view.
- Provide a default view that suits most users.
const [toggleSwitchChecked, setToggleSwitchChecked] = useState<boolean>(false);
return (
<TableToolbar
customViews={
<ToggleSwitch label="Label" value={toggleSwitchChecked} onChange={setToggleSwitchChecked} />
}
/>
);
#Usage with exports
Enable users to download table data in various formats (CSV, Excel, etc.).
Learn how to use the normal exporter and the CSV exporter in the guidelines for the Table component.
Best Practices:
- Clearly label the button as "Export" or use a recognizable download icon.
- For multiple export formats (CSV, Excel, etc.), use an Action menu
return (
<TableToolbar
exports={
<Button>
<Icon>
<IconDownload />
</Icon>
<InlineText>Export</InlineText>
</Button>
}
/>
);
#Usage with actions, filter, search, custom views and exports
Combine all functionalities for comprehensive user control.
Best Practices:
- Logical Grouping:
- Group related functions (e.g., actions on the left, filtering/search/views/export on the right).
- Use visual separators (divider or spacing) to distinguish groups.
- Visual Hierarchy: Employ spacing, size, and position to indicate the relative importance of actions.
// Search
const [searchValue, setSearchValue] = useState("");
const searchTypeItems = ["URL", "Title"];
const [selectedSearchType, setSelectedSearchType] = useState<string | undefined>(
searchTypeItems[0]
);
// Filters
const countries = [
{ id: "DK", name: "Denmark" },
{ id: "SE", name: "Sweden" },
{ id: "NO", name: "Norway" },
{ id: "FI", name: "Finland" },
];
const devices = [
{ id: "desktop", name: "Desktop" },
{ id: "mobile", name: "Mobile" },
{ id: "tablet", name: "Tablet" },
{ id: "laptop", name: "Laptop" },
];
const [filters, setFilters] = useState({
country: countries[0],
devices: [devices[0], devices[1]],
});
const [filterGroup, activeFilters] = useFilterGroup(filters, setFilters, [
{
label: "Country",
name: "country",
property: "country",
stringify: ({ country }) => country?.name,
items: countries.map((country) => ({ title: country.name, value: country })),
compareFn: (a, b) => a.id === b.id,
},
{
label: "Devices",
name: "devices",
property: "devices",
stringify: ({ devices }) =>
(devices || []).length > 0 ? devices?.map((b) => b.name).join(", ") : undefined,
items: devices.map((device) => ({ title: device.name, value: device })),
compareFn: (a, b) => a.id === b.id,
},
]);
return (
<TableToolbar
actions={
<>
<Button variant="primary" onClick={() => console.log("some primary action")}>
Primary
</Button>
<Button variant="secondary" onClick={() => console.log("some secondary action")}>
Secondary
</Button>
</>
}
filter={filterGroup}
activeFilters={activeFilters}
search={
<InputFieldWithSlug
aria-label="Search the table"
placeholder="Search"
name="searchInput"
value={searchValue}
onChange={setSearchValue}
leftSlug={
<Select
items={searchTypeItems.map((x) => ({ value: x, title: x }))}
value={selectedSearchType}
onChange={setSelectedSearchType}
hideClearButton
aria-label="Search in URL or title"
/>
}
rightSlug={
<Button onClick={() => console.log(searchValue)} aria-label="Submit search">
<Icon>
<IconSearch />
</Icon>
</Button>
}
/>
}
customViews={
<Popover
popoverContent={(id) => (
<div id={id}>
<Content>Custom view content here</Content>
<Popover.Footer>
<ActionBar
primary={{
children: "Confirm",
onClick: console.log,
}}
cancel={{
children: "Cancel",
onClick: console.log,
}}
/>
</Popover.Footer>
</div>
)}
buttonContent={
<>
<Icon>
<IconColumn />
</Icon>
<InlineText>Custom views</InlineText>
</>
}
hideChevron
/>
}
exports={
<Button>
<Icon>
<IconDownload />
</Icon>
<InlineText>Export</InlineText>
</Button>
}
/>
);
#Properties
Property | Description | Defined | Value |
---|---|---|---|
actionsOptional | element Actions/Buttons to be displayed in the table toolbar | ||
filterOptional | element Filter to be displayed in the table toolbar | ||
searchOptional | element Search to be displayed in the table toolbar | ||
customViewsOptional | element Custom views to be displayed in the table toolbar | ||
exportsOptional | element Export options to be displayed in the table toolbar | ||
activeFiltersOptional | element Active filters | ||
data-observe-keyOptional | string Unique string, used by external script e.g. for event tracking | ||
classNameOptional | string Custom className that's applied to the outermost element (only intended for special cases) | ||
styleOptional | object Style object to apply custom inline styles (only intended for special cases) |
#Guidelines
#Best practices
#Style
- Siteimprove Design System: Adhere to Siteimprove's guidelines for color, typography, and spacing. If you are not using a component from Fancy, match the styling of your
TableToolbar
to existing components for visual consistency. - Focus on actions that operate on the entire table and directly support its primary purpose.
- Use universally recognized icons .
- The toolbar should adapt seamlessly to different screen sizes and devices.
- Order of Toolbar Items: (Left to right) Primary Actions > Secondary Actions > Filter > Search > Custom Views > Export
#Do not use when
#Accessibility
Explore detailed guidelines for this component: Accessibility Specifications